package strung

import (
	"sync"
	"time"

	"starsine.cn/appTpl/cmn"
	"starsine.cn/appTpl/cmn/timermgr"
	"starsine.cn/appTpl/svclog/src/db"
	. "starsine.cn/appTpl/svclog/src/logproc/defs"
)

// type SvcLogSum struct {
// 	InstanceID string
// 	SvcLogLine
// }

type Strung struct {
	InstanceID string
	size       int
	len        int
	data       []*SvcLogLine

	expire time.Time
	tmID   int64
	tm     *timermgr.TimerMgr

	sync.RWMutex
}

func CreateStrung(size int) *Strung {
	p := new(Strung)

	p.size = size
	p.len = 0
	p.data = make([]*SvcLogLine, p.size)

	p.expire = time.Now().Add(time.Minute)
	p.tmID = -1
	p.tm = cmn.GetTm()

	return p
}

func (p *Strung) Start() {
	p.checkPeriod()
}

func (p *Strung) End() {
	p.tm.CancelTimer(p.tmID)
}

func (p *Strung) checkAndFlush(params interface{}) {
	p.Flush()
}

func (p *Strung) checkPeriod() {
	p.tmID = p.tm.AddPeriodTimer(
		time.Duration(3),
		timermgr.NewOnTimeOut(p.checkAndFlush,
			nil,
		))
}

func (p *Strung) Flush() {
	p.RWMutex.Lock()
	defer p.RWMutex.Unlock()

	if p.len <= 0 {
		return
	}

	// to flush
	data := make([]interface{}, p.len)
	for i := 0; i < p.len; i++ {
		data[i] = p.data[i]
	}
	db.InsertMany(data)
	p.len = 0

	if p.tmID != -1 {
		p.tm.CancelTimer(p.tmID)
	}
	p.checkPeriod()
}

func (p *Strung) Join(d *SvcLogLine) {
	p.RWMutex.Lock()
	defer p.RWMutex.Unlock()

	p.data[p.len] = d
	p.len++

	if p.len >= p.size {
		p.Flush()
	}

	p.expire = time.Now().Add(time.Minute)
}

func (p *Strung) IsExpired() bool {
	p.RWMutex.RLock()
	defer p.RWMutex.RUnlock()

	return !p.expire.After(time.Now())

}
